← C++ 高级程序设计(2020) 2020-C++高级程序设计-C++ 输入输出 2020-07-01 约 32 分钟阅读 阅读 — 次
C++ 输入输出
1. I/O
输入输出流:包含在头文件<iostream>中
开头需要进行#include<iostream>
1.1. 标准库对象
对象
功能
istream:cin
处理输入
ostream:cout
处理输出
ostream:cerr
处理错误
ostream:clog
保证log
2. 输入
2.1. 输入原理
程序的输入都键入一个缓冲区,即输入缓冲区。
键盘输入结束后,会将数据存入缓冲区,之后cin函数直接从输入缓冲区取数据
问题在于:缓冲区中有残留数据的时候,cin输入流直接从缓冲区拿数据。
2.2. cin
>>是流提取符,以空格,\t(Tab),\n(回车)为终止
往往使用来赋值给变量
cin的变量类型可以为int、float、char、char*、string等诸多类型。
2.2.1. 数组输入
1 2 3 4 5 6 7 8 9 for (int i = 0 ;i < n; i++){ cin >> nums[i] }while (cin >> n){ nums[i] = n; i ++; }
2.2.2. 解决格式化输入问题
1 2 3 4 5 char c;int x1,x2,y1,y2 cin >> c >> x1 >> c >> x2 >> c >> c >> c >> y1 >> c >> y2 >> c >> c;(这个很重要)
2.2.3. get方法
1 2 3 4 5 6 int get () ;istream& get (char & c) ;istream& get (char * s, streamsize n) ;istream& get (char * s, streamsize n, char delim) ;istream& get (streambuf& sb) ;istream& get (streambuf& sb, char delim) ;
结束符默认为enter,结束字符串的读写
字符串最后一个为\0,并且对空格不敏感。
get方法并不会将结束符从缓冲区丢弃 :务必注意是结束符!未必是回车。
1 2 3 4 5 6 7 8 9 10 11 12 cin.get (x); cin.get (y);char ch1,ch2[10 ]; cout<<"请输入字符串:" <<endl; cin.get (ch2,6 ); cin.get (ch1); out<<ch2<<endl; cout<<ch1<<"\n" <<(int )ch1<<endl;
直接回车在上面程序中会出现错误输出(越界),处理方法cin.clear():但是不会清理终止符。
1 2 3 4 5 6 7 8 9 10 11 cin.get (ch, 3 , 'a' ); cin.get (ch2); cin.get (ch, 3 , 'a' ); ch2 = cin.get (); cout << ch2 << ' ' << (int )ch2 << endl; cin.get ();
2.2.4. cin.getline()
cin.getline(字符数组名,接收长度,结束符)
cin.get()超长后不会影响cin的操作,而cin.getline()如果超长会导致之后cin的错误。
2.2.5. getline()
getline(istream is,string str,结束符)
2.3. cin异常处理机制
2.3.1. 标志位
定义在IOS类中
他们不是储存异常状态常量,而是对应状态为的掩码。
名称
二进制显示
功能
failbit
001
输入(输出)流出现致命错误,不可挽回
eofbit
010
已经到达文件尾
badbit
100
输入(输出)流出现非致命错误,可挽回
goodbit
000
流状态完全正常,各异常标志位都为0
1 2 3 4 cout << ios::failbit << endl; cout << ios::eofbit << endl; cout << ios::badbit << endl; cout << ios::goodbit << endl;
2.3.2. rdstate()
rdstate():获取标志变量的值
1 2 3 4 5 6 7 void TestFlags ( ios& x ) { cout << ( x.rdstate ( ) & ios::badbit ) << endl; cout << ( x.rdstate ( ) & ios::failbit ) << endl; cout << ( x.rdstate ( ) & ios::eofbit ) << endl; cout << endl; }
2.3.3. bool ios::fail()const
1 or true if rdstate & failbit is nonzero, otherwise 0 or false. (引用msdn)
其中rdstate即通过rdstate()取得的标识变量的值,与failbit相与,即取得failbit标志位的值,如果结果非零则放回true,否则返回false。即该函数返回failbit的状态,将标志位状态通过bool值返回。
2.3.4. bool ios::bad() const
1 or true if rdstate & badbit is nonzero; otherwise 0. (引用msdn)
与fail()相似。
2.3.5. bool ios::good()const
1 or true if rdstate == goodbit (no state flags are set), otherwise, 0 orfalse. (引用msdn)
改函数取goodbit的情况,即三个标志位都0(即没有任何异常情况)时返回true,否则返回false。
2.3.6. voidios::clear(iostate _State=goodbit)
该函数用来重置标识变量,_State是用来重置的值,默认为goodbit,即默认时将所有标志位清零。用户也可以传进参数,如:clear(failbit),这样就将标识变量置为failbit(即:001)。
我们一般是用它的默认值,当cin出现异常,我们用该函数将所有标志位重置。如果cin出现异常,没有重置标志的话没法执行下一次的cin操作。如上一节的程序2的测试二为什么第二次输入操作没有执行?程序8中 cin>>ch 为什么没有执行?都是这个原因!!!
所以经常在程序中使用 cin.clear(), 为了重置错误标志!
2.3.7. void ios::setstate(iostate_State)
这个函数也是用来设置标识变量的,但与clear()不同。clear()是将所有标志清零,在置以参数新的标志。而该函数不清零其他的标志,而只是将参数对应的标志位置位。这个函数不是经常使用,这里不再赘述。
2.3.8. 例子
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 #include <iostream> using namespace std; int main () { char ch, str[20 ]; cin.getline (str, 5 ); cout<<"flag1:" <<cin.good ()<<endl; cin.clear (); cout<<"flag1:" <<cin.good ()<<endl; cin>>ch; cout<<"str:" <<str<<endl; cout<<"ch :" <<ch<<endl; return 0 ; }
【分析】程序执行结束还是只执行了一次读操作,cin>>ch还是没有从键盘读取数据,但是与程序8中不同,这里打印了ch的值为’5’,而且在cin>>ch之前已经清楚了错误标志,也就是cin>>ch的读操作实际上执行了。这就是前面讲的cin读取数据的原理:它是直接从输入缓冲区中取数据的。此例中,第一次输入"12345",而getline(str, 5)根据参数’5’只取缓冲区中的前4个字符,所以str取的是"1234",而字符’5’仍在缓冲区中,所以cin>>ch直接从缓冲区中取得数据,没有从键盘读取数据!
也就是当前一次读取数据出错后,如果缓冲区没有清空的话,重置错误标志还不够!要是能将缓冲区的残留数据清空了就好了哦!下面我们再来看一个很重要的函数!
2.3.9. basic_istream&ignore(streamsize _Count = 1, int_type _Delim = traits_type::eof());
Causes a number of elements to be skipped from the current readposition
Parameters:
_Count, The number of elements to skip from the current read position.
_Delim, The element that, if encountered before count, causes ignore to returnand allowing all elements after _Delim to be read. (引用msdn)\
这个函数用来丢弃输入缓冲区中的字符,第一参数定义一个数,第二个参数定义一个字符变量。下面解释一下函数是怎样执行的:函数不停的从缓冲区中取一个字符,并判断是不是_Delim,如果不是则丢弃并进行计数,当计数达到_Count退出,如果是则丢弃字符退出。例:cin.ignore(5, ‘a’); 函数将不断从缓冲区中取一个字符丢弃,直到丢弃的字符数达到5或者读取的字符为’a’。下面我们看个程序例子:
1 2 3 4 5 6 7 8 9 #include <iostream> using namespace std;int main () { char ch; cin.ignore (5 , 'a' ); cin.get (ch); cout << (int )ch << endl; return 0 ; }
例子见参考三
2.3.10. 丢弃一个字符
cin.ignore():删除缓冲区的第一个字符
2.3.11. 清除缓冲区
cin.ignore(1024,'\n');
cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
2.4. 函数输出
2.4.1. getchar()
getchar();获得一个字符
可以读取到空格\n等等的字符。
2.4.2. putchar()
putchar();输出一个字符
3. 输出
3.1. 标准输出流 cout
<<流插入符
std::endl:换行,可以输出一个或者多个,等价于\n
3.1.1. 格式化输出
1 2 3 4 5 6 7 8 9 10 #include <iomanip> cout << hex << 10 << "" << oct << 8 ; cout << setorecison (4 ) << 1.11111 ; cout << setw (6 ) << right << 10 ; cout << year << '-' << setw (2 ) << setfill ('0' ) << month << ‘-’ << std::setw (2 ) << std::setfill ('0' ) << day;
3.2. 使用命名空间std
using namespace std;来直接使用
cin,cout是C++标准库内置函数但不是关键字。
3.3. 函数输出
scanf(“%d”,&a);
printf(“%d”,a);
4. 控制符
5. 不同类别的I/O处理
基于函数库的I/O
基于类库的I/O
5.1. I/O流库的三类输入/输出
控制台I/O:标准I/O设备(cin、cout、cerr、clog)
文件I/O
字符串I/O
5.2. 重定向
1 2 3 4 5 6 7 8 9 10 11 12 13 ifstream in ("in. txt" ) ; streambuf * cinbuf = cin. rdbuf (); cin. rdbuf ( in. rdbuf ());ofstream out (" out. txt " ) ; streambuf * coutbuf = cout. rdbuf (); cout. rdbuf ( out. rdbuf ()); string word; cin >> word; cout << word << " " ; cin. rdbuf ( cinbuf ); cout. rdbuf ( coutbuf ); cin >> word; cout << word;
5.3. 对操作符<<和>>的重载
对自定义类的对象的I/O
全局(友元)函数重载
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 class CPoint2D { double x, y; public : friend ostream& operator << (ostream&, CPoint2D &); }; ostream& operator << (ostream& out, CPoint2D& a){ out << a.x << "," << a.y << endl; return out; } CPoint2D a; cout << a;class CPoint3D : public CPoint2D { double z; } CPoint3D b; cout << b;class CPoint3D : public CPoint2D { double z; friend ostream& operator << (ostream &, CPoint3D &); } ostream& operator << (ostream& out, CPoint3D & b){ out << b.x << "," << b.y <<"," << b.z << endl; return out; }
5.4. IO处理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 class CPoint2D { double x, y; public : virtual void display (ostream& out) { out << x << "," << y << endl; } }; ostream& operator << (ostream& out, CPoint2D &a){ a.display (out); return out; }class CPoint3D : public CPoint2D{ double z; public : void display (ostream& out) { CPoint2D::display (); out << "," << z << endl; } };
5.5. Virtualizing constructors 虚拟化构造器
虚函数
构造器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 class NLComponent {…};class TextBlock :public NLComponent {…};class Graphic :public NLComponent {…};class NewsLetter { public : NewsLetter (istream& str){ while (str) components.push_back (readComponent (str)); } static NLComponent * readComponent (istream& str) ; NewsLetter (const NewsLetter& rhs){ for (list<NLComponent *>::iterator it=rhs.component.begin ();it != rhs.component.end (); ++it ) component.push_back (); } private : list<NLComponent *> components; }virtual NLComponent *clone () const = 0 ;virtual TextBlock *clone () const { return new TextBlock (*this ); }virtual Graphic *clone () const { return new Graphic (*this ); } NewsLetter::NewsLetter ( const NewsLetter& rhs){ for ( list<NLComponent *>::iterator it=rhs.component.begin (); it != rhs.component.end (); ++it ) component.push_back ((*it)->clone ()); }class BST {};class BalancedBST : public BST {};void printBSTArray (ostream& s, const BST array[], int numElements) { for (int i=0 ; i < numElements; i++) s << array[i]; } BalancedBST bBSTArray[10 ];printBSTArray (cout, bBSTArray, 10 );
6. 读文件
1 2 3 4 5 6 7 8 9 10 11 ifstream infile ("file_name" ) ;if (!infile.is_open ()){ cout << "未成功打开文件" << endl; }int arr[26 ] = { 0 };char c; infile >> c;while (!infile.eof ()) { infile >> c; }
7. 泛型用一个方法输出double和int
如果(a - int(a)) > 1E-7:则认为是double
否则为int
8. 参考
cin、cin.get()、cin.getline()、getline()的区别
评论